#include "Main.h"
#include "DataPreprocessing.h"
#include "KMeans.h"
#include "OutlierDetection.h"

///////////////////////////////////////////////////////////////////////////////////////////////////

int main(int argnum, char **argv) {

	/********[Defined Object of classes]*************/
	DataProprocessing dp;	// Data preprocessing object
	Kmeans km;				//Kmeans object
	OutlierDetection od;	//Outliewr detection object
	/***********************************************/

	/*************[Time variables]******************/
	clock_t tt1, tt2;	//Total time
	clock_t d1, d2;		//Data preprocessing time
	clock_t t1, t2;		//kmeans++ time
	clock_t s1, s2;		//kmeans time
	clock_t p1, p2;		//kmeans + kmeans++ time
	clock_t o1, o2;		//outlier detection time
	
	int diff_tt = 0;
	int diff_dp = 0;
	int diff_kmpp = 0;
	int diff_km = 0;	
	int diff_km_kmpp = 0;
	int diff_od = 0;	

	string diff_tt_str = "";
	string diff_dp_str = "";
	string diff_km_str = "";
	string diff_kmpp_str = "";
	string diff_od_str = "";
	
	/***********************************************/
	
	tt1 = clock() / CLOCKS_PER_SEC;
	//======================= [ DataPreprocessing part ] ===================================	
	d1 = clock() / CLOCKS_PER_SEC;	
	struct StructOfdataPre {
		int number;
		int base;
		int selectNum;
		string path;
		vector<vector<string>> memEle;
		vector<vector<string>> vmemEle;
		vector<vector<string>> vmemEle_doneBase;
		vector<vector<string>> vmemEle_doneAll;
		vector<string> MN;
		vector<vector<double>> arrNum;
		vector<double> sim_vector;
		string filename;
		string inputKMpp;
		char* inputFile;
		char* outputFile;
	};

	StructOfdataPre var_dp;
	
	//=================[MENU]===============================
	menuBuildUp(var_dp.inputFile,var_dp.outputFile);
	//======================================================

	//cout <<endl<<"=====================[ Phase 1 : DataPreprocessing]====================="<<endl<<endl;
	//				
	//		var_dp.memEle = dp.readFile(var_dp.inputFile); // Read I/O file
	//		var_dp.vmemEle = dp.readFileVertically(var_dp.memEle);// convert to a form vertically
	//		//begin for converting categorical into numeric
	//		dp.checkAttType(var_dp.vmemEle);
	//		var_dp.base = dp.findBaseCateAtt(var_dp.vmemEle);
	//		var_dp.MN = dp.buildMN(var_dp.vmemEle);
	//		dp.buildMatrix(var_dp.vmemEle,var_dp.memEle);
	//		dp.calculateSimilarity();
	//		var_dp.sim_vector = dp.readCoStrSim();
	//		var_dp.arrNum = dp.varianceNumeric(var_dp.base,var_dp.vmemEle,var_dp.memEle);
	//		var_dp.selectNum = dp.selectSSw(var_dp.arrNum);
	//		var_dp.vmemEle_doneBase = dp.assignMeantoBase(var_dp.selectNum,var_dp.vmemEle);
	//		var_dp.vmemEle_doneAll = dp.quantifiedFunc(var_dp.sim_vector,var_dp.vmemEle_doneBase,var_dp.vmemEle);
	//		//end for converting

	//		////Output of phase 1 : data preprocessing
	//		//var_dp.inputKMpp = dp.writeIutputKMeanPP(var_dp.outputFile,var_dp.vmemEle_doneAll); // write input of K-means++ => string text
	//		//dp.writeOutput(var_dp.vmemEle_doneAll); //show output to console
	//		dp.writeIntoFile(var_dp.outputFile,var_dp.vmemEle_doneAll); // write CSV file
	//		dp.clearMemory();
	//		
	//		d2 = clock() / CLOCKS_PER_SEC;
	//		diff_dp = 1000 * (d2 - d1);
	//		diff_dp_str = counterTime(diff_dp);			
	//		cout<<diff_dp<<endl;
	//		writeLogIODP(diff_dp_str, var_dp.base, var_dp.vmemEle[var_dp.base][0]);
			//================================================================================================================================================

			//======================= [ K-means++ part ] ===================================

			p1 = clock()  / CLOCKS_PER_SEC;
			cout <<endl<< "=========================[ Phase 2 : K-means++]========================="<<endl<<endl;
			int count = 0;
			vector<vector<double>> points;
			vector<string> sortCID_return_kmpp;
			vector<int> sortPID_return_kmpp;
			vector<int> pointsID;
			vector<vector<double>> centers_km;
			vector<vector<double>> centers_kpp;
			vector<string> sortCID_return_km;
			vector<int> sortPID_return_km;
			vector<int> startCenter_km;
			vector<int> startCenter_kmpp;

			//Set points
			points = km.loadDataFromFile(var_dp.outputFile);
			pointsID = km.SetPointID(points);
			p2 = clock() / CLOCKS_PER_SEC;

			if(kmeans) {
				s1 = clock() / CLOCKS_PER_SEC;

				LOG("\r\nProcessing K-means.......\r\n");
				km.clearAllMemory();
				centers_km = km.SeedKmeansCenter(points);
				count = km.FormCluster(centers_km, points);
				km.writeValuesInputPhase3("kmeans",sortCID_return_km,sortPID_return_km,startCenter_km);
				LOG("\r\nK-means is done!\r\n");

				s2 = clock() / CLOCKS_PER_SEC;
				diff_km = 1000*(s2 - s1);
			}

			if(kmeanpp) {
				t1 = clock() / CLOCKS_PER_SEC;
				
				LOG("\r\nProcessing K-means++.......\r\n");
				km.clearAllMemory();
				centers_kpp = km.SeedKmeansPPCenter(points);
				count = km.FormCluster(centers_kpp, points);
				km.writeValuesInputPhase3("kmeanspp",sortCID_return_kmpp, sortPID_return_kmpp,startCenter_kmpp);

				LOG("\r\nK-means++ is done!\r\n");

				t2 = clock() / CLOCKS_PER_SEC;
				diff_kmpp = 1000*(t2 - t1);
			}

				diff_km_kmpp = 1000*(p2 - p1);

				if(diff_km != 0) {
					diff_km = diff_km + diff_km_kmpp;
					diff_km_str = counterTime(diff_km);
					cout<<"diff_km_str : "<<diff_km_str<<endl;
				}

				if(diff_kmpp != 0) {
					diff_kmpp = diff_kmpp + diff_km_kmpp;
					diff_kmpp_str = counterTime(diff_kmpp);
					cout<<"diff_kmpp_str : "<<diff_kmpp_str<<endl;
				}

			writeLogIOKM(count,startCenter_km,startCenter_kmpp,diff_km_str,diff_kmpp_str, K_cluster, sortCID_return_kmpp, sortPID_return_kmpp,sortCID_return_km, sortPID_return_km);
			//===============================================================================================================================================
			//======================= [ Outlier Detetion  part ] ===================================
								o1 = clock() / CLOCKS_PER_SEC;	

			cout <<endl<< "======================[ Phase 3 : Outlier Detetion]======================"<<endl<<endl;

				vector<double> nearMinPoint_dist;		
				vector<double> ird_p;
				vector<double> otherNearMinPoint_dist;	
				vector<double> pq_distance;
				vector<double> ird_sub_p;
				vector<double> LO_Cluster;
				vector<double> lof_p;

				vector<int> nearMinPoint;
				vector<int> otherNearMinPoint;
				vector<int> ird_n;
				vector<int> outlier_pointID;

				vector<string> current_q;
				vector<string> local_outlier_status;
				vector<string> outlier_centerID;

				vector<vector<double>> meanCluster;		
				vector<vector<double>> current_q_NN_dist;
				vector<vector<double>> dist_vector;

				vector<vector<int>> pointEachCluster;
				vector<vector<int>> pID_vector;				
				vector<vector<int>> current_q_NN;

				int CenterSize = K_cluster;
				int PointSize = points.size();
				int AttSize = points[0].size();
			//	points = km.loadDataFromFile(var_dp.outputFile);
			//	pointsID = km.SetPointID(points);
				
				od.SetGlobalVariable("kmeanspp",points,pointsID);		
				//od.calculateAllDistanceAllPoints(pointsID,points);
				meanCluster = od.FindMeanCluster(CenterSize, PointSize, AttSize, pointEachCluster);			
				LO_Cluster = od.CalculatedLO(AttSize,pointEachCluster, meanCluster);
				od.DetectLocalOutlier(LO_Cluster, pointEachCluster);
				//od.RemoveOutlierPoints(pointEachCluster); //optional
				od.setupLOF(pointEachCluster);
				od.collectMinPtsPointSameCluster(pointEachCluster, nearMinPoint,nearMinPoint_dist);
				od.collectMinPtsPointOtherCluster(pointEachCluster, otherNearMinPoint, otherNearMinPoint_dist);
				od.formMinPtsPointAllCluster(nearMinPoint,nearMinPoint_dist,otherNearMinPoint, otherNearMinPoint_dist,pID_vector,dist_vector);
				od.readFileFormAllCluster(pID_vector,dist_vector);					
				//od.calculateAllDistance(pointsID,points,pID_vector);
				od.findMinPtsOfQ(pID_vector, current_q, current_q_NN, current_q_NN_dist);
				pq_distance = od.defineReachDist(1,current_q, current_q_NN, current_q_NN_dist);
				ird_n = od.countN(pID_vector);
				ird_p = od.CalculateIRD(pq_distance,current_q,ird_n);
				ird_sub_p = od.processIRDQ(current_q,current_q_NN,pID_vector);
				lof_p = od.calculateLOF(current_q,ird_p,ird_sub_p,ird_n);
				local_outlier_status = od.determineOutlierStatus(lof_p);
				od.returnUseValue(outlier_pointID,outlier_centerID);

				o2 = clock() / CLOCKS_PER_SEC;
				diff_od = 1000 * (o2 - o1);
				diff_od_str = counterTime(diff_od);
				
				tt2 = clock() / CLOCKS_PER_SEC;		
				writeLogIOOD(MinPts, diff_od_str, outlier_pointID,outlier_centerID,lof_p,local_outlier_status,sortCID_return_kmpp, sortPID_return_kmpp);
				//===============================================================================================================================================				
				/*writeLogIO(diff_dp_str, diff_km_str , diff_kmpp_str, diff_od_str, diff_tt_str, var_dp.base, 
							var_dp.vmemEle[var_dp.base][0],K_cluster,outlier_pointID,outlier_centerID,
							lof_p,local_outlier_status,sortCID_return_kmpp, sortPID_return_kmpp);*/
				
				diff_tt = 1000*((int)tt2 - (int)tt1) / CLOCKS_PER_SEC;
				diff_tt_str = counterTime(diff_tt);
				writeLogIOSummary(diff_tt_str);
				waitEndKey();

				return 0;
			}
